{
 "cells": [
  {
   "cell_type": "markdown",
   "id": "3f7dc4cf",
   "metadata": {},
   "source": [
    "## 闭包\n",
    "- 是指一个函数引用了其外部作用域的变量，并且这个外部函数已经执行完毕了。这个被引用的变量会与内层函数“绑定”在一起，即使外部函数已经返回，其局部变量应该被销毁，但闭包仍然可以记住并访问这些变量\n",
    "\n",
    "**闭包就是一个能“记住”它被创建时环境的函数**\n",
    "\n",
    "**nonlocal**用于修改外部变量（Python3+）\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "b86eb48f",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "1\n",
      "2\n",
      "1\n",
      "(<cell at 0x0000020878BF6800: int object at 0x00007FFDE3239328>,)\n",
      "2\n"
     ]
    }
   ],
   "source": [
    "# 优势：\n",
    "# 数据封装：count 被隐藏在create_counter函数内部，外部代码无法直接访问或修改它\n",
    "# 保持状态：每次调用create_counter()都会创建一个全新的、独立的计数器实例，他们会各自维护自己的count状态，互不干扰\n",
    "def create_counter():\n",
    "    count = 0\n",
    "    def counter():\n",
    "        nonlocal count\n",
    "        count += 1\n",
    "        return count\n",
    "    return counter\n",
    "\n",
    "my_counter = create_counter()\n",
    "print(my_counter())\n",
    "print(my_counter())\n",
    "\n",
    "your_counter = create_counter()\n",
    "print(your_counter())\n",
    "# print(my_counter())\n",
    "\n",
    "# 使用 __closure__探查是否存在闭包, 不存在则为None\n",
    "print(your_counter.__closure__)\n",
    "# 查看闭包记住变量的值\n",
    "print(my_counter.__closure__[0].cell_contents)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "1fe7ca58",
   "metadata": {},
   "source": [
    "### 闭包中存在延迟绑定的问题"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "id": "c9e65c65",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "8\n",
      "8\n",
      "8\n",
      "8\n",
      "8\n",
      "-----------------------------\n",
      "0\n",
      "2\n",
      "4\n",
      "6\n",
      "8\n"
     ]
    }
   ],
   "source": [
    "# 延迟绑定的问题\n",
    "# case 1:\n",
    "def create_multipliers():\n",
    "    multipliers = []\n",
    "    for i in range(5):\n",
    "        # 此处的i没有被定义，一直被修改\n",
    "        def multiplier(x):\n",
    "            return i * x\n",
    "        multipliers.append(multiplier)\n",
    "    return multipliers\n",
    "\n",
    "for multiplier in create_multipliers():\n",
    "    print(multiplier(2))\n",
    "\n",
    "print(\"-----------------------------\")\n",
    "\n",
    "# case 2 解决方法\n",
    "def create_multipliers():\n",
    "    multipliers = []\n",
    "    for i in range(5):\n",
    "        # 在传参时已经定义，则不会被修改\n",
    "        def multiplier(x, i=i):\n",
    "            return i * x\n",
    "        multipliers.append(multiplier)\n",
    "    return multipliers\n",
    "\n",
    "for multiplier in create_multipliers():\n",
    "    print(multiplier(2))"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "f6e9bb42",
   "metadata": {},
   "source": [
    "## 装饰器是高级版的闭包\n",
    "- 装饰器是一个接收函数作为参数，并返回一个新函数的高阶函数。允许在不修改原函数代码的情况下，为函数增加新功能"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "c5f44f0b",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Hello, Tianyu\n",
      "say_hello函数运行时间为1.0011秒\n",
      "say_hello\n",
      "\n",
      "    用于打招呼的函数\n",
      "    \n"
     ]
    }
   ],
   "source": [
    "import time\n",
    "from functools import wraps\n",
    "\n",
    "def timer(func):\n",
    "    @wraps(func) # 使用wraps装饰func, 使它能将元信息\n",
    "    def wrapper_func(*args, **kargs):\n",
    "        start_time = time.time()\n",
    "        result = func(*args, **kargs)\n",
    "        end_time = time.time()\n",
    "        print(f\"{func.__name__}函数运行时间为{end_time - start_time:.4f}秒\")\n",
    "        return result\n",
    "    return wrapper_func\n",
    "\n",
    "@timer\n",
    "def say_hello(name):\n",
    "    \"\"\"\n",
    "    用于打招呼的函数\n",
    "    \"\"\"\n",
    "    time.sleep(1)\n",
    "    print(f\"Hello, {name}\")\n",
    "\n",
    "# 手动包装\n",
    "# t_say = timer(say_hello)\n",
    "# t_say(\"Qiu Rongcan\")\n",
    "\n",
    "# 使用语法糖的形式\n",
    "say_hello(\"Tianyu\")\n",
    "# 会隐藏原函数的信息\n",
    "print(say_hello.__name__)\n",
    "print(say_hello.__doc__)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 17,
   "id": "6b4b06e9",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "fast_test运行时间为1.0019731708780455毫秒\n",
      "==================================================\n",
      "slow_test运行时间为1.2003283500671387秒\n"
     ]
    }
   ],
   "source": [
    "# 带参数的装饰器\n",
    "from functools import wraps\n",
    "import time\n",
    "\n",
    "def timer(unit=\"s\"):\n",
    "    def actual_decorator(func):\n",
    "        @wraps(func)\n",
    "        def wrapper(*args, **kargs):\n",
    "            start = time.time()\n",
    "            result = func(*args, **kargs)\n",
    "            end = time.time()\n",
    "            duration = end - start\n",
    "            if unit == \"s\":\n",
    "                unit_str = \"秒\"\n",
    "            elif unit == \"ms\":\n",
    "                unit_str = \"毫秒\"\n",
    "                duration *= duration\n",
    "            \n",
    "            print(f\"{func.__name__}运行时间为{duration}{unit_str}\")\n",
    "\n",
    "            return result\n",
    "        \n",
    "        return wrapper\n",
    "    return actual_decorator\n",
    "\n",
    "@timer(unit='ms')\n",
    "def fast_test():\n",
    "    time.sleep(1)\n",
    "\n",
    "@timer(unit='s')\n",
    "def slow_test():\n",
    "    time.sleep(1.2)\n",
    "\n",
    "fast_test()\n",
    "print(\"=\"*50)\n",
    "slow_test()\n"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "4e61a434",
   "metadata": {},
   "source": [
    "## 多线程（Threading）\n",
    "允许同一个进程中并发执行多个线程，由于GIL的存在，通常不适用于计算密集型任务（CPU-bound），适用于I/O密集型任务（I/O-bound），比如网络请求、文件读写等需要等待的操作\n",
    "- GIL是python中的一个互斥锁，它规定在任何时刻，只有一个线程可以执行Python字节码"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "9427425d",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "MyThreadtest 0\n",
      "MyThreadtest 1\n",
      "MyThreadtest 2\n",
      "MyThreadtest 3\n",
      "MainThreadmain 0\n",
      "MyThreadis_alive True\n",
      "MyThreadtest 4\n",
      "MainThreadmain 1\n",
      "MyThreadis_alive False\n",
      "MainThreadmain 2\n",
      "MyThreadis_alive False\n",
      "MainThreadmain 3\n",
      "MyThreadis_alive False\n",
      "MainThreadmain 4\n",
      "MyThreadis_alive False\n"
     ]
    }
   ],
   "source": [
    "# case 1\n",
    "import threading\n",
    "import time\n",
    "\n",
    "# 给线程的命名默认为Threa-N的形式\n",
    "# 可以自定义命名形式\n",
    "# 代码结束则线程自动结束\n",
    "# 线程阻塞，join()方法\n",
    "# 增加daemon属性，设置daemon=True，主线程结束，则子线程也马上结束\n",
    "\n",
    "def test():\n",
    "    for i in range(5):\n",
    "        print(threading.current_thread().name + \"test\", i)\n",
    "        time.sleep(0.5)\n",
    "\n",
    "thread = threading.Thread(target=test, name=\"MyThread\")\n",
    "# 线程启动\n",
    "thread.start()\n",
    "# thread 线程运行完才执行后续的线程 可以设置阻塞的时间\n",
    "thread.join(1.5)\n",
    "\n",
    "for i in range(5):\n",
    "    print(threading.current_thread().name + \"main\", i)\n",
    "    print(thread.name + \"is_alive\", thread.is_alive())\n",
    "    time.sleep(1)\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "89d2a9bc",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "线程 0 开始\n",
      "线程 1 开始\n",
      "线程 2 开始\n",
      "线程 0 结束\n",
      "线程 1 结束\n",
      "线程 2 结束\n"
     ]
    }
   ],
   "source": [
    "# case 2 基本使用\n",
    "import threading\n",
    "import time\n",
    "\n",
    "def worker(num):\n",
    "    print(f\"线程 {num} 开始\")\n",
    "    time.sleep(1.5)\n",
    "    print(f'线程 {num} 结束')\n",
    "\n",
    "\n",
    "threads = []\n",
    "for i in range(3):\n",
    "    t = threading.Thread(target=worker, args=(i, ))\n",
    "    threads.append(t)\n",
    "    t.start()\n",
    "\n",
    "# 保证子线程结束，然后主线程才结束，并且按顺序\n",
    "for t in threads:\n",
    "    t.join()\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "45110167",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "t_0 正在执行\n",
      "t_1 正在执行\n",
      "t_2 正在执行\n"
     ]
    }
   ],
   "source": [
    "import threading\n",
    "import time\n",
    "\n",
    "\n",
    "class MyThread(threading.Thread):\n",
    "    def __init__(self, group = None, target = None, name = None, args = ..., kwargs = None, *, daemon = None):\n",
    "        super().__init__(group, target, name, args, kwargs, daemon=daemon)\n",
    "\n",
    "    def run(self):\n",
    "        print(f\"{self.name} 正在执行\")\n",
    "        # super().run()\n",
    "        try:\n",
    "            if self._target:\n",
    "                self._target(*self._args, **self._kwargs)\n",
    "        finally:\n",
    "            print(f\"{self.name} 执行完成\")\n",
    "\n",
    "# class MyThread(threading.Thread):\n",
    "\n",
    "#     def __init__(self, target, name, args):\n",
    "#         super().__init__(None, target, name, args)\n",
    "#         self.name = name\n",
    "    \n",
    "#     def run(self):\n",
    "#         print(f\"{self.name} 正在执行\")\n",
    "#         super().run()\n",
    "\n",
    "\n",
    "def worker(num):\n",
    "    print(f\"线程 {num} 开始\")\n",
    "    time.sleep(1.5)\n",
    "    print(f'线程 {num} 结束')\n",
    "\n",
    "\n",
    "threads = []\n",
    "for i in range(3):\n",
    "    t = MyThread(target=worker, name=f\"t_{i}\", args=(i, ))\n",
    "    threads.append(t)\n",
    "    t.start()\n",
    "\n",
    "# 保证子线程结束，然后主线程才结束，并且按顺序\n",
    "for t in threads:\n",
    "    t.join()\n"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "f496663d",
   "metadata": {},
   "source": [
    "### 线程锁"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "f3f50a09",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "10000\n"
     ]
    }
   ],
   "source": [
    "# 简单看两个例子，线程不同步的后果\n",
    "import threading\n",
    "import time\n",
    "\n",
    "\n",
    "lock = threading.Lock()\n",
    "count = 0\n",
    "def unsafe_increment():\n",
    "    global count\n",
    "    # 没有这lock运行会不同步\n",
    "    with lock:\n",
    "        for _ in range(1000):\n",
    "            temp = count\n",
    "            temp = temp + 1\n",
    "            count = temp\n",
    "    # count += 1\n",
    "\n",
    "threads = [threading.Thread(target=unsafe_increment) for _ in range(10)]\n",
    "for t in threads:\n",
    "    t.start()\n",
    "\n",
    "for t in threads:\n",
    "    t.join()\n",
    "\n",
    "print(count)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "b81b9f2f",
   "metadata": {},
   "source": [
    "### 线程间的通信"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "f2136731",
   "metadata": {},
   "source": [
    "## 多进程\n",
    "一个程序中创建多个独立的进程来同时执行任务，每个进程都有自己独立的内存空间和Python解释器，因此可以绕过GIL限制，实现真正的并行计算\n",
    "- 每个进程都有自己独立的内存空间  \n",
    "进程存在的挑战：\n",
    "- 资源开销大\n",
    "- 进程间通信复杂\n",
    "- 上下文切换成本高"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "id": "fac49ddb",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "所有进程执行完毕！\n"
     ]
    }
   ],
   "source": [
    "import multiprocessing\n",
    "import time\n",
    "import os\n",
    "\n",
    "\n",
    "def worker(task_id):\n",
    "    \"\"\"\n",
    "    子进程要执行的任务\n",
    "    \"\"\"\n",
    "    print(f\"进程 {task_id} (PID: {os.getpid()}) 开始执行\")\n",
    "    time.sleep(2)\n",
    "    print(f\"进程 {task_id} 执行完毕\")\n",
    "\n",
    "\n",
    "if __name__ == \"__main__\":\n",
    "    processes = []\n",
    "\n",
    "    for i in range(3):\n",
    "\n",
    "        p = multiprocessing.Process(target=worker, args=(i,))\n",
    "        processes.append(p)\n",
    "        p.start()\n",
    "    \n",
    "    for p in processes:\n",
    "        p.join()\n",
    "\n",
    "    print(\"所有进程执行完毕！\")\n",
    "\n",
    "\n"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "df374caf",
   "metadata": {},
   "source": [
    "### 使用进程池Pool\n",
    "当需要创建大量进程池时，使用进程池可以更好的管理资源"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "a446ba24",
   "metadata": {},
   "outputs": [],
   "source": [
    "import multiprocessing\n",
    "import time\n",
    "\n",
    "def square_number(n):\n",
    "    time.sleep(0.5)\n",
    "    result = n * n\n",
    "    print(f\"{n} 的平方是 {result}\")\n",
    "    return result\n",
    "\n",
    "if __name__ == \"__main__\":\n",
    "    with multiprocessing.Pool(processes=4)  as pool:\n",
    "        results = []\n",
    "        for i in range(10):\n",
    "            result = pool.apply_async(square_number, args=(i, ))\n",
    "            results.append(result)\n",
    "        output = [result.get() for result in results]\n",
    "\n",
    "    \n",
    "    print(output)"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "base",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.12.7"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 5
}
